package com.xaicode.learn.ads.linkedlist;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;

/**
 * double linked list
 *
 * @author Locker xaicode@sina.com
 */
@Slf4j
public class DoubleLinkedList {
    public static void main(String[] args) {
        DLL dll = new DLL();
        Node node1 = new Node(1, "k1", "v1");
        Node node2 = new Node(2, "k2", "v2");
        Node node3 = new Node(3, "k3", "v3");
        Node node4 = new Node(4, "k4", "v4");
        dll.add(node1);
        dll.add(node2);
        dll.add(node3);
        dll.add(node4);
//        dll.list();
//        System.out.println("------------");

        Node node5 = new Node(4, "k5", "v5");
        Node node6 = new Node(6, "k6", "v6");
        dll.update(node5);
        dll.update(node6);
        dll.list();
        System.out.println("------------");

//        dll.remove(4);
//        dll.list();
//        dll.remove(7);

    }

    /**
     * single linked list
     */
    static class DLL {
        /**
         * all nodes data
         */
        private Node nodes = new Node();

        public void add(Node node) {
            Node ite = nodes;
            // find the last node
            while (ite.next != null) {
                ite = ite.next;
            }
            ite.next = node;
            node.pre = ite;
        }

        /**
         * FIXME 双向链表删除不存在节点时，列表头元素丢失
         */
        public void update(Node newNode) {
            Node temp = nodes.next;
            // whether newNode.no found
            boolean positionFound = false;
            while (temp != null) {
                if (temp.no.equals(newNode.no)) {
                    positionFound = true;
                    break;
                }
                temp = temp.next;
            }

            if (positionFound) {
                temp.key = newNode.key;
                temp.val = newNode.val;
            } else {
                System.out.printf("target node number %s is not existed", newNode.no);
            }
        }

        public void remove(int number) {
            Node temp = nodes.next;
            // whether select node found
            boolean positionFound = false;
            while (temp != null) {
                if (temp.no == number) {
                    positionFound = true;
                    break;
                }
                temp = temp.next;
            }

            if (positionFound) {
                temp.pre.next = temp.next;
                // temp is not the last node
                if (temp.next != null) {
                    temp.next.pre = temp.pre;
                }
            } else {
                System.out.printf("target node number %s is not existed", number);
            }
        }

        public void list() {
            // skip the first null node
            Node temp = nodes.next;
            while (temp != null) {
                System.out.println(temp);
                temp = temp.next;
            }
        }
    }

    /**
     * data node for linked list
     */
    @Setter
    @Getter
    @ToString
    static class Node {
        /**
         * current node number
         */
        Integer no;

        String key;

        Object val;

        /**
         * next node.
         * It will be the last node when this <code>next</code> equals <code>null</code>
         */
        @ToString.Exclude
        Node next;

        /**
         * next node.
         */
        @ToString.Exclude
        Node pre;

        public Node() {
            this.no = 0;
            this.key = "";
            this.val = "";
        }

        public Node(Integer no, String key, Object val) {
            this.no = no;
            this.key = key;
            this.val = val;
        }
    }

}